package com.mrzhou.core.tool.yml;

import com.mrzhou.core.tool.utils.Assert;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.util.*;
import java.util.stream.Stream;

/**
 * 用以处理{@link org.springframework.context.annotation.PropertySource} 注解读取yaml格式的配置文件
 * 使用注解时请指定name属性， 因为如果出现多个PropertySource时，且没有指定name属性时会出现后面加载的PropertySource覆盖之前的
 * @author qiang.zhou
 */
public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource encodedResource) throws IOException {
        Resource resource = encodedResource.getResource();
        String fileName = resource.getFilename();
        Assert.isNotBlank(name, String.format("使用PropertySource注解时，请指定name属性, 在加载: %s", fileName));
        List<PropertySource<?>> sources  = new YamlPropertySourceLoader().load(fileName, resource);
        if(sources.isEmpty()) {
            return emptyPropertySource(name);
        } else {
            Map<String, Object> map = new HashMap(16);
            Iterator<PropertySource<?>> var7 = sources.iterator();
            while (var7.hasNext()) {
                PropertySource<?> propertySource = var7.next();
                map.putAll(((MapPropertySource)propertySource).getSource());
            }
            return new OriginTrackedMapPropertySource(getSourceName(name), map);
        }
    }

    private static PropertySource<?> emptyPropertySource(@Nullable String name) {
        return new MapPropertySource(getSourceName(name), Collections.emptyMap());
    }

    /**
     * PropertySource 的key, 有多个使用此factory解析配置时，请指定name且不能重复
     * 否者会出现覆盖的情况
     * @param names
     * @return
     */
    private static String getSourceName(String... names) {
        return Stream.of(names).filter(StringUtils::isNotBlank).findFirst().orElse("CloudYamlPropertySource");
    }

}
